/******************************************************************************
 * FileName:    gwin_global_data.c
 * Desc:        全局变量
 *
 *
 * Author:      Lin
 * Notes:
 *
 ******************************************************************************/

/*-------------------------- Includes ---------------------------------------*/
#include "gwin_global_data.h"
#include "gwin_motor_task.h"


/*-------------------------- Macro Definitions ------------------------------*/
#define LOCAL_DEBUG_EN                      ( 0 )
#if LOCAL_DEBUG_EN
#define GWIN_DEBUG(...)                     USER_DEBUG(__VA_ARGS__)
#else
#define GWIN_DEBUG(...)
#endif


/*-------------------------- Type Declarations ------------------------------*/

/*-------------------------- Global Variables -------------------------------*/
/**
 * @brief 系统参数
 */
extern system_param_t system_param;


/**
 * @brief 系统参数上传表
 *          为了减轻服务器压力，少上报参数
 */
const system_upload_map_t system_upload_map[] =
{
    [SYS_UPLOAD_INDEX_PRODUCT_CFG] =            { sizeof(system_param.product_cfg),                     (uint8_t*)(&system_param.product_cfg),                      NULL,                                                               spec_notify_product_cfg,        },
    [SYS_UPLOAD_INDEX_CURRENT_POSITION] =       { sizeof(system_param.curtain.current_position),        (uint8_t*)(&system_param.curtain.current_position),         (uint8_t*)(&system_param.system_upload.last.current_position),      spec_notify_current_position,   },
    [SYS_UPLOAD_INDEX_TARGET_POSITION] =        { sizeof(system_param.curtain.target_position),         (uint8_t*)(&system_param.curtain.target_position),          (uint8_t*)(&system_param.system_upload.last.target_position),       spec_notify_target_position,    },
    [SYS_UPLOAD_INDEX_DIRECTION] =              { sizeof(system_param.curtain.direction),               (uint8_t*)(&system_param.curtain.direction),                (uint8_t*)(&system_param.system_upload.last.direction),             spec_notify_direction,          },
    [SYS_UPLOAD_INDEX_SPEED_LEVEL] =            { sizeof(system_param.curtain.speed_level),             (uint8_t*)(&system_param.curtain.speed_level),              (uint8_t*)(&system_param.system_upload.last.speed_level),           spec_notify_speed_level,        },
    [SYS_UPLOAD_INDEX_STROKE_MIN] =             { sizeof(system_param.setting.stroke_min),              (uint8_t*)(&system_param.setting.stroke_min),               NULL,                                                               spec_notify_stroke_min,         },
    [SYS_UPLOAD_INDEX_STROKE_MAX] =             { sizeof(system_param.setting.stroke_max),              (uint8_t*)(&system_param.setting.stroke_max),               NULL,                                                               spec_notify_stroke_max,         },
    [SYS_UPLOAD_INDEX_NODE_MODE] =              { sizeof(system_param.setting.node_mode),               (uint8_t*)(&system_param.setting.node_mode),                NULL,                                                               spec_notify_node_mode,          },
};

static const gwin_product_cfg_t defualt_product_cfg = { 0 };
static const reboot_state_t defualt_reboot_state = { 0 };
static const network_t defualt_network_provisioned = { 0x00 };
static const system_upload_t defualt_system_upload_last = {
    .wait = 0,
    .last =
    {
        .current_position = INVALID_U8,
        .target_position = INVALID_U8,
        .direction = INVALID_U8,
        .speed_level = INVALID_U8,
    }

};
const system_param_setting_t defualt_system_param_setting = {
    .upload_total = 0,
};


/**
 * @brief 固定场景 参数表
 *      最多创建 16 条记录，总数据长度不超过 512 字节，写入数据， 数据长度需要 4 字节对齐
 */
static const system_param_default_t system_param_default_map[] =
{
    [RECORD_ID_PRODUCT_CFG] =           { sizeof(system_param.product_cfg),         (uint8_t*)(&system_param.product_cfg),          (uint8_t*)(&defualt_product_cfg),           },
    [RECORD_ID_REBOOT_STATE] =          { sizeof(system_param.reboot_state),        (uint8_t*)(&system_param.reboot_state),         (uint8_t*)(&defualt_reboot_state),          },
    [RECORD_ID_NETWORK] =               { sizeof(system_param.network),             (uint8_t*)(&system_param.network),              (uint8_t*)(&defualt_network_provisioned),   },
    [RECORD_ID_SYSTEM_UPLOAD] =         { sizeof(system_param.system_upload),       (uint8_t*)(&system_param.system_upload),        (uint8_t*)(&defualt_system_upload_last),    },
    [RECORD_ID_SETTING] =               { sizeof(system_param.setting),             (uint8_t*)(&system_param.setting),              (uint8_t*)(&defualt_system_param_setting),  },
};
static const uint8_t system_param_default_map_cnt = sizeof(system_param_default_map) / sizeof(system_param_default_map[0]);


/*-------------------------- Local Variables --------------------------------*/

/*-------------------------- Functions Declarations -------------------------*/
static void gwin_custom_system_param_init(void);
static void gwin_custom_record_check_reboot_state(void);
static void gwin_custom_record_reset_product_mark(void);
static void gwin_custom_record_reset_all_force(void);

static void gwin_custom_record_check_product_mark(void);


/*-------------------------- Functions Definitions --------------------------*/
/**
 * @brief 用户存储区 检查
 */
void gwin_custom_record_check(void)
{
    uint16_t record_len_sum = 0;

    if (system_param_default_map_cnt > 16)
    {
        // 最多创建 16 条记录
        GWIN_DEBUG("Error : custom record count over 16!!!");
        while(1);
    }

    for (uint8_t i = RECORD_ID_MIN; i < system_param_default_map_cnt; i++)
    {
        if (system_param_default_map[i].size >= 256)
        {
            // SDK读写flash最大256，具体看实际情况
            GWIN_DEBUG("Error : custom record id[%d] size[%d] more then 256 byte!!!", i, system_param_default_map[i].size);
            while(1);
        }

        if (system_param_default_map[i].size < 4)
        {
            // 优化内存，支持小于 4 字节
            GWIN_DEBUG("Warn : custom record id[%d] size[%d] less then 4 byte!!!", i, system_param_default_map[i].size);
        }
        else if (system_param_default_map[i].size % 4 != 0)
        {
            // 数据长度需要 4 字节对齐
            GWIN_DEBUG("Error : custom record id[%d] size[%d] not align at 4 byte!!!", i, system_param_default_map[i].size);
            while(1);
        }

        record_len_sum += system_param_default_map[i].size;
        if (record_len_sum > 512)
        {
            // 总数据长度不超过 512 字节
            GWIN_DEBUG("Error : custom record over 512 byte!!!");
            while(1);
        }
    }
}

/**
 * @brief 用户存储区 读取
 */
void gwin_custom_record_load(void)
{
    gwin_custom_record_check();

    memset(&system_param, 0x00, sizeof(system_param_t));

    gwin_custom_record_check_product_mark();

    for (uint8_t i = RECORD_ID_MIN; i < system_param_default_map_cnt; i++)
    {
        if (system_param_default_map[i].size < 4)
        {
            // 优化内存，支持小于 4 字节
            uint32_t value = 0;
            if (MI_SUCCESS != miio_record_read(i, (uint8_t *)&value, sizeof(value)))
            {
                GWIN_DEBUG("Load Failed : id[%d] size[%d]", i, system_param_default_map[i].size);
                gwin_custom_record_reset(i);
            }
            else
            {
                memcpy(system_param_default_map[i].memory_addr, &value, system_param_default_map[i].size);
            }
        }
        else
        {
            if (MI_SUCCESS != miio_record_read(i, system_param_default_map[i].memory_addr, system_param_default_map[i].size))
            {
                GWIN_DEBUG("Load Failed : id[%d] size[%d]", i, system_param_default_map[i].size);
                gwin_custom_record_reset(i);
            }
        }
    }

    gwin_custom_record_check_reboot_state();

    gwin_custom_system_param_init();
}

/**
 * @brief 用户存储区 保存
 */
void gwin_custom_record_save(uint16_t record_id)
{
    if (system_param_default_map[record_id].size < 4)
    {
        // 优化内存，支持小于 4 字节
        uint32_t value = 0;
        memcpy(&value, system_param_default_map[record_id].memory_addr, system_param_default_map[record_id].size);
        miio_record_write(record_id, (uint8_t *)&value, sizeof(value));
    }
    else
    {
        miio_record_write(record_id, system_param_default_map[record_id].memory_addr, system_param_default_map[record_id].size);
    }
}

/**
 * @brief 用户存储区 重置
 */
void gwin_custom_record_reset(uint16_t record_id)
{
    miio_record_delete(record_id);
    memcpy(system_param_default_map[record_id].memory_addr, system_param_default_map[record_id].defalut_addr, system_param_default_map[record_id].size);

    if (system_param_default_map[record_id].size < 4)
    {
        // 优化内存，支持小于 4 字节
        uint32_t value = 0;
        memcpy(&value, system_param_default_map[record_id].memory_addr, system_param_default_map[record_id].size);
        miio_record_create(record_id, sizeof(value));
        miio_record_write(record_id, (uint8_t *)&value, sizeof(value));
    }
    else
    {
        miio_record_create(record_id, system_param_default_map[record_id].size);
        miio_record_write(record_id, system_param_default_map[record_id].memory_addr, system_param_default_map[record_id].size);
    }
}

/**
 * @brief 用户存储区 重置
 */
void gwin_custom_record_reset_all(void)
{
    static const uint8_t record_id_reserve_map[] = { RECORD_ID_NETWORK, };
    static const uint8_t record_id_reserve_cnt = sizeof(record_id_reserve_map) / sizeof(record_id_reserve_map[0]);

    uint8_t reserve_index = 0;
    for (uint8_t i = RECORD_ID_MIN; i < system_param_default_map_cnt; i++)
    {
        if (reserve_index < record_id_reserve_cnt && i == record_id_reserve_map[reserve_index])
        {
            reserve_index++;
            continue;
        }
        gwin_custom_record_reset(i);
    }
}


/**
 * @brief 用户存储区 检查产品标识符
 *          产品标识符判断，防止烧录不同产品，匹配不对，则强制复位所有参数
 */
static void gwin_custom_record_check_product_mark(void)
{
    uint8_t reset = 0;

    product_mark_t product_mark;
    memset(&product_mark, 0x00, sizeof(product_mark_t));
    if (MI_SUCCESS != miio_record_read(RECORD_ID_PRODUCT_MARK, (uint8_t *)&product_mark, sizeof(product_mark_t)))
    {
        reset = 1;
    }
    else
    {
        uint8_t len = MAX(strlen((char *)product_mark.model_name), strlen(GWIN_PRODUCT_MODEL));
        if (memcmp(product_mark.model_name, GWIN_PRODUCT_MODEL, len) != 0
                || product_mark.reset_all_force_force != PRODUCT_MARK_RESET_ALL_FORCE_FORCE)
        {
            reset = 1;
        }
        else if (product_mark.reset_all_force != PRODUCT_MARK_RESET_ALL_FORCE)
        {
            gwin_custom_record_reset_all_force();
        }
        else if (product_mark.reset_all != PRODUCT_MARK_RESET)
        {
            gwin_custom_record_reset_product_mark();
            gwin_custom_record_reset_all();
        }
    }

    if (reset)
    {
        gwin_custom_record_reset_all_force_force();
    }
}

/**
 * @brief 用户存储区 重置 产品标识符
 */
static void gwin_custom_record_reset_product_mark(void)
{
    product_mark_t product_mark;
    memset(&product_mark, 0x00, sizeof(product_mark_t));
    memcpy(product_mark.model_name, GWIN_PRODUCT_MODEL, strlen(GWIN_PRODUCT_MODEL));
    product_mark.reset_all = PRODUCT_MARK_RESET;
    product_mark.reset_all_force = PRODUCT_MARK_RESET_ALL_FORCE;
    product_mark.reset_all_force_force = PRODUCT_MARK_RESET_ALL_FORCE_FORCE;

    miio_record_delete(RECORD_ID_PRODUCT_MARK);
    miio_record_create(RECORD_ID_PRODUCT_MARK, sizeof(product_mark_t));
    miio_record_write(RECORD_ID_PRODUCT_MARK, (uint8_t *)&product_mark, sizeof(product_mark_t));
}

/**
 * @brief 用户存储区 重置 强制
 *          用于产品已经烧录后，修改flash分区大小
 */
static void gwin_custom_record_reset_all_force(void)
{
    gwin_custom_record_reset_product_mark();

    static const uint8_t record_id_reserve_map[] = { RECORD_ID_PRODUCT_CFG, RECORD_ID_NETWORK, };
    static const uint8_t record_id_reserve_cnt = sizeof(record_id_reserve_map) / sizeof(record_id_reserve_map[0]);

    uint8_t reserve_index = 0;
    for (uint8_t i = RECORD_ID_MIN; i < system_param_default_map_cnt; i++)
    {
        if (reserve_index < record_id_reserve_cnt && i == record_id_reserve_map[reserve_index])
        {
            reserve_index++;
            continue;
        }
        gwin_custom_record_reset(i);
    }
}
/**
 * @brief 用户存储区 重置 强制强制
 *          用于已经烧录不同的产品，必须把整个flash都擦掉，还要等待协议栈初始化以后重置网络
 */
void gwin_custom_record_reset_all_force_force(void)
{
    gwin_custom_record_reset_product_mark();

    // 重置所有参数
    for (uint8_t i = RECORD_ID_MIN; i < system_param_default_map_cnt; i++)
    {
        gwin_custom_record_reset(i);
    }
}


/**
 * @brief 用户存储区 重启状态 判断
 */
static void gwin_custom_record_check_reboot_state(void)
{
    // 看门狗重启
    if (gwin_watch_dog_reboot())
    {
        system_param.reboot_state.reason = REBOOT_REASON_WDG;
    }

    GWIN_DEBUG("reboot_state : reason = %d", system_param.reboot_state.reason);

    if (system_param.reboot_state.reason != REBOOT_REASON_NONE)
    {
        if (system_param.reboot_state.reason > REBOOT_REASON_RESTORE_STATE)
        {
            system_param.reboot_restore_state = 1;
        }

        system_param.reboot_state.reason = REBOOT_REASON_NONE;
        gwin_custom_record_save(RECORD_ID_REBOOT_STATE);
    }
}

/**
 * @brief 用户存储区 重启状态 保存
 */
void gwin_custom_record_save_reboot_state(uint8_t reason)
{
    system_param.reboot_state.reason = reason;
    gwin_custom_record_save(RECORD_ID_REBOOT_STATE);
}


/**
 * @brief 系统参数初始化
 */
static void gwin_custom_system_param_init(void)
{

}
/**
 * @brief 系统参数初始化
 */
void gwin_custom_system_param_init_after_board_init(void)
{

}
/**
 * @brief 系统参数初始化
 */
void gwin_custom_system_param_init_after_ble_init(void)
{

}


/*-------------------------- END OF FILE ------------------------------------*/

